package com.example.bluetoothgateway;

import androidx.appcompat.app.AppCompatActivity;

import android.bluetooth.BluetoothAdapter;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;

import com.clj.fastble.BleManager;
import com.clj.fastble.callback.BleScanCallback;
import com.clj.fastble.data.BleDevice;
import com.clj.fastble.scan.BleScanRuleConfig;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MainActivity extends AppCompatActivity {
    private final String TAG = "MainActivity";
    private final String WATCH_NAME = "HEART_BELT";
    private final String LOCAL_MAC_ADDRESS = "AABBCCDDEEFF";
    /* 设备三元组信息 */
    private final String PRODUCTKEY = "ipoyzQ3Zdzy";
    private final String DEVICENAME = "xiaomi5_ipad";
    private final String DEVICESECRET = "2e7d0087c642b927e73a2c2c08681851";

    /* 自动Topic, 用于上报消息 */
    final private String PUB_TOPIC = "/" + PRODUCTKEY + "/" + DEVICENAME + "/user/pub";
    /* 自动Topic, 用于接受消息 */
    final private String SUB_TOPIC = "/" + PRODUCTKEY + "/" + DEVICENAME + "/user/sub";

    /* 阿里云Mqtt服务器域名 */
    final String host = "tcp://" + PRODUCTKEY + ".iot-as-mqtt.cn-shanghai.aliyuncs.com:443";
    private String clientId;
    private String userName;
    private String passWord;

    MqttAndroidClient mqttAndroidClient;

    public ConcurrentLinkedQueue bleDeviceQueue = new ConcurrentLinkedQueue();
    public ConcurrentLinkedQueue bleDeviceMacQueue = new ConcurrentLinkedQueue();
    ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();

    @Override
    protected void onDestroy() {
        super.onDestroy();
        service.shutdown();
        //timer.cancel();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /* 获取Mqtt建连信息clientId, username, password */
        AiotMqttOption aiotMqttOption = new AiotMqttOption().getMqttOption(PRODUCTKEY, DEVICENAME, DEVICESECRET);
        if (aiotMqttOption == null) {
            Log.e(TAG, "device info error");
        } else {
            clientId = aiotMqttOption.getClientId();
            userName = aiotMqttOption.getUsername();
            passWord = aiotMqttOption.getPassword();
        }

        /* 创建MqttConnectOptions对象并配置username和password */
        MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
        mqttConnectOptions.setUserName(userName);
        mqttConnectOptions.setPassword(passWord.toCharArray());

        /* 创建MqttAndroidClient对象, 并设置回调接口 */
        mqttAndroidClient = new MqttAndroidClient(getApplicationContext(), host, clientId);
        mqttAndroidClient.setCallback(new MqttCallback() {
            @Override
            public void connectionLost(Throwable cause) {
                Log.i(TAG, "connection lost");
            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                Log.i(TAG, "topic: " + topic + ", msg: " + new String(message.getPayload()));
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {
                Log.i(TAG, "msg delivered");
            }
        });

        /* Mqtt建连 */
        try {
            mqttAndroidClient.connect(mqttConnectOptions,null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.i(TAG, "connect succeed");

                    subscribeTopic(SUB_TOPIC);
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.i(TAG, "connect failed");
                }
            });

        } catch (MqttException e) {
            e.printStackTrace();
        }

        BleManager.getInstance().init(getApplication());
        BleManager.getInstance()
                .enableLog(true)
                .setReConnectCount(1, 5000)
                .setOperateTimeout(5000);

        BleScanRuleConfig scanRuleConfig = new BleScanRuleConfig.Builder()
                //.setServiceUuids(serviceUuids)      // 只扫描指定的服务的设备，可选
                .setDeviceName(true, WATCH_NAME)         // 只扫描指定广播名的设备，可选
                //.setDeviceMac(MAC)                // 只扫描指定mac的设备，可选
                .setAutoConnect(false)               // 连接时的autoConnect参数，可选，默认false
                .setScanTimeOut(0)              // 扫描超时时间，可选，默认10秒
                .build();
        BleManager.getInstance().initScanRule(scanRuleConfig);

        Button sendMessageButton = findViewById(R.id.sendMessageButton);
        sendMessageButton.setOnClickListener(view -> {
            publishMessage("hello IoT");
        });

        Button startButton = findViewById(R.id.startButton);
        startButton.setOnClickListener(view -> {
            startScan();
        });

        Button stopButton = findViewById(R.id.stopButton);
        stopButton.setOnClickListener(view -> {
            stopScan();
        });

        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    ConcurrentLinkedQueue m_queue = bleDeviceQueue;
                    int len = m_queue.size();
                    JSONObject packet_obj = new JSONObject();
                    JSONObject base_info_obj = new JSONObject();
                    /**  base_info  */
                    base_info_obj.put("time",getTime());
                    base_info_obj.put("total",len);
                    base_info_obj.put("timestamp","000000");
                    base_info_obj.put("id", LOCAL_MAC_ADDRESS);
                    /**  upload_datas  */
                    JSONArray upload_datas_array = new JSONArray();
                    for(int i=0; i<len; i++)
                    {
                        JSONObject upload_datas_elem = new JSONObject();
                        BleDevice bleDevice = (BleDevice) m_queue.poll();
                        upload_datas_elem.put("mac",bleDevice.getMac().replaceAll(":",""));
                        upload_datas_elem.put("channel","37");
                        upload_datas_elem.put("rssi",bleDevice.getRssi()+"");
                        upload_datas_elem.put("name",bleDevice.getName());
                        upload_datas_elem.put("type","06");/* LE General Discoverable Mode, BR/EDR not supported */
                        upload_datas_elem.put("MFR",BytesConvert.bytesToHexString(Arrays.copyOfRange(bleDevice.getScanRecord(),5,28)));
                        upload_datas_array.put(upload_datas_elem);
                    }
                    packet_obj.put("base_info",base_info_obj);
                    packet_obj.put("upload_datas",upload_datas_array);
                    Log.d(TAG,packet_obj.toString());
                    publishMessage(packet_obj.toString());
                    bleDeviceQueue.clear();
                    bleDeviceMacQueue.clear();
                }catch (Exception e){

                }
            }
        },3,1, TimeUnit.SECONDS);
    }

    public void publishMessage(String payload) {
        try {
            if (mqttAndroidClient.isConnected() == false) {
                mqttAndroidClient.connect();
            }

            MqttMessage message = new MqttMessage();
            message.setPayload(payload.getBytes());
            message.setQos(0);
            mqttAndroidClient.publish(PUB_TOPIC, message,null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.i(TAG, "publish succeed!");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.i(TAG, "publish failed!");
                }
            });
        } catch (MqttException e) {
            Log.e(TAG, e.toString());
            e.printStackTrace();
        }
    }

    public void subscribeTopic(String topic) {
        try {
            mqttAndroidClient.subscribe(topic, 0, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.i(TAG, "subscribed succeed");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.i(TAG, "subscribed failed");
                }
            });

        } catch (MqttException e) {
            e.printStackTrace();
        }
    }


    public void startScan() {
        BleManager.getInstance().scan(new BleScanCallback() {
            @Override
            public void onScanStarted(boolean success) {
                Log.d(TAG, "onScanStarted："+success);
            }@Override
            public void onLeScan(BleDevice bleDevice) {
                if(WATCH_NAME.equals(bleDevice.getName()))
                {
                    if(!bleDeviceMacQueue.contains(bleDevice.getMac()))
                    {
                        Log.d(TAG, "onLeScan："+bleDevice.getMac());
                        bleDeviceQueue.offer(bleDevice);
                        bleDeviceMacQueue.offer(bleDevice.getMac());
                    }
                }
            }
            @Override
            public void onScanning(BleDevice bleDevice) {
                Log.d(TAG, "onScanning："+bleDevice.getMac());
            }
            @Override
            public void onScanFinished(List<BleDevice> scanResultList) {
                Log.d(TAG, "onScanFinished："+scanResultList.size());
            }
        });
    }

    public void stopScan() {
        BleManager.getInstance().cancelScan();
        Log.d(TAG,"cancelScan");
        bleDeviceQueue.clear();
        bleDeviceMacQueue.clear();
    }

    public String getTime(){
        long timecurrentTimeMillis=System.currentTimeMillis()/1000;
        //SimpleDateFormat sdfTwo =new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault());
        //String time = sdfTwo.format(timecurrentTimeMillis);
        return timecurrentTimeMillis+"";
    }
}